package jp.sourceforge.akjrcp.snack;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import jp.sourceforge.akjrcp.commons.util.JapaneseUtils;
import jp.sourceforge.akjrcp.snack.PitchToMIDI.NoteData;
import jp.sourceforge.akjrcp.subtitle.StandardSubObject;
import vocaloid.AutoPhoneticsUtils;
import vocaloid.ListValue;
import vocaloid.PhoneticsUtils;
import vocaloid.VocaloidMIDI;
import vocaloid.VocaloidNote;
import vocaloid.VocaloidSystem;
import vocaloid.VocaloidTrack;


public class PitchToVocaloidMIDI extends PitchToMIDI{
	private int maxBendSens=24;
	private int preMeasure=1;
//	private int vel=64; //velocity
	private int bre=0;
	private int bri=64;
	private int cle=0;
	private int ope=127;
	private int gender=64;
	private int por=64;

	private boolean reduceNoVoice=true;
	private boolean detailPitch;	//parse pitchs
	private boolean detailDynamics;

	private int detailLevel=1;
	
	private String dynamicChangeStrategy;
	
	private boolean addStereoTrack;
	private int stereoTrackMixer=-50;	//-5.0
	
	private boolean separateBreathTrack;
	private boolean ignoreBreathDynamics=true;
	private int  defaultBreathDynamics=32;
	private boolean copyAsBreathTrack;
	private String copyAsBreathPhonetics="br1";
	private String copyAsBreathPhonetics2="br2";
	private boolean doubleBreathTrack;
	private boolean doubleBreathOnSplit;
	private int stereoTrackPan=64;
	
	private boolean autoNNPhonetics;
	


	protected int getEspsesTick(){
		return pertick/(16*detailLevel);
	}
	
	public PitchToVocaloidMIDI(){
		super();
		setParseVelocity(true);
	}
	
	private VocaloidTrack createVocaloidTrack(int offset,List<NoteData> noteDataList,int currentShiftNote){
		VocaloidTrack track=new VocaloidTrack();
		
		
		
		track.getEpRResidualBPList().add(new ListValue(offset,bre));
		track.getEpRESlopeBPList().add(new ListValue(offset,bri));
		track.getEpRESlopeDepthBPList().add(new ListValue(offset,cle));
		track.getOpeningBPList().add(new ListValue(offset,ope));
		track.getGenderFactorBPList().add(new ListValue(offset,gender));
		track.getPortamentoTimingBPList().add(new ListValue(offset,por));
		char lastChar=JapaneseUtils.HIRAGANA_A;
		
		

		
		for (int i = 0; i < noteDataList.size(); i++) {
			boolean noVoice=false;	//only su:'s S'
			NoteData note=noteDataList.get(i);
			int startTick=offset+(int)((double)note.getStart()*240/pertick);
			int noteLength=((note.getEnd()-note.getStart())*240/pertick);
			//memo
			//i tried 480 but,no change
			/*
			if(note.getComment().equals(""+JapaneseUtils.HIRAGANA_DE)){
				log.info("**note:"+note);
				for(int j=0;j<note.getPitchNoteDatas().size();j++){
					PitchNoteData data=note.getPitchNoteDatas().get(j);
					
					log.info(data);
				}
			
			}*/
			//force set for empty comment
			
			if(note.getComment()==null || note.getComment().equals("")){
				note.setComment(""+JapaneseUtils.HIRAGANA_A);
			}
			//log.trace("comment:"+((int)note.getComment().charAt(0))+","+((int)JapaneseUtils.KIGOU_NOBASHI));
			if(note.getComment().equals(""+JapaneseUtils.HIRAGANA_SU)){//take care of voice and no voice
				
				lastChar=note.getComment().charAt(0);
				
				if(shouldNoVoice(note)){
					noVoice=true;
					track.addNote(new VocaloidNote(note.getNote()+JAVA_NOTE_OFFSET+currentShiftNote,startTick,noteLength,note.getComment(),PhoneticsUtils.S+" "+PhoneticsUtils.S_LARGE,defaultVelocity));
				}else{
					track.addNote(new VocaloidNote(note.getNote()+JAVA_NOTE_OFFSET+currentShiftNote,startTick,noteLength,note.getComment(),PhoneticsUtils.hiraganaToPhonetics(note.getComment()),defaultVelocity));
				}
			}else if(note.getComment().equals(""+JapaneseUtils.KIGOU_NOBASHI)){
				char comment=JapaneseUtils.getHiraganaVowel(lastChar);
				
				track.addNote(new VocaloidNote(note.getNote()+JAVA_NOTE_OFFSET+currentShiftNote,startTick,noteLength,note.getComment(),PhoneticsUtils.hiraganaToPhonetics(""+comment),defaultVelocity));
				
			}else{
				//if tu ignore tu.
				if(note.getComment().equals(JapaneseUtils.HIRAGANA_SMALL_TU)){
				lastChar=note.getComment().charAt(0);
				}else{
					lastChar=note.getComment().charAt(note.getComment().length()-1);//add last char	
				}
				track.addNote(new VocaloidNote(note.getNote()+JAVA_NOTE_OFFSET+currentShiftNote,startTick,noteLength,note.getComment(),PhoneticsUtils.hiraganaToPhonetics(note.getComment()),defaultVelocity));
			}
			//track.getDynamicsBPList().add(new ListValue(vs,note.getVelocity()));
			//log.info("s:"+note.getVelocityBent().size());
			
			double p=(double)noteLength/note.getVelocityBent().size();
			
			if(detailDynamics){
			
			for(int j=0;j<note.getVelocityBent().size();j++){
				int v=note.getVelocityBent().get(j);
				if(noVoice && reduceNoVoice){//special reduce for novoice 
					//now considerring should I 's S'  be reduced
					//track.getDynamicsBPList().add(new ListValue(vs+(int)(j*p),v/2));
					//v/=2;
					//2009.01.10 i have no idea what i'm doing.
					if(v<3){
						v=3;//limit min	//TODO to be set
					}
					//step=1
					if(j==note.getVelocityBent().size()-1){
						//last one
						double s=v/p;
						for(int k=0;k<p;k++){
							double tmpv=v-s*k;
							track.getDynamicsBPList().add(new ListValue(startTick+(int)(j*p)+k,(int)tmpv));
						}
					}else{
						track.getDynamicsBPList().add(new ListValue(startTick+(int)(j*p),v));
					}
				}else{
					track.getDynamicsBPList().add(new ListValue(startTick+(int)(j*p),v));
				}
				
			}
			
			
			}
			
			
			
			
			
			
			if(detailPitch){
				//add initial

			for(int j=0;j<note.getPitchNoteDatas().size();j++){
				double offsetNote=0;
				if(!normalizePitch){
				PitchNoteData data=note.getPitchNoteDatas().get(j);
				 offsetNote=data.getNote()-note.getNote();
				offsetNote+=data.getLevel();
				}else{
					int count=0;
					double total=0;
					
					for(int k=j-normalizePitchRange;k<j+normalizePitchRange;k++){
						if(k>=0 && k<note.getPitchNoteDatas().size()){
							count++;
							 PitchNoteData data=note.getPitchNoteDatas().get(k);
							 total+=data.getNote()-note.getNote();
							 total+=data.getLevel();
						}else{
							if(containPitchOverRange){
								 count++;//triple
								 //count+=3;//triple
								 total+=0;
							}
						}
					}
					
					offsetNote=total/count;
					//log.trace("offset:"+offsetNote+"total:"+total+"count:"+count);
				}
				int v=(int) ((ListValue.PITCH_BEND_MAX/maxBendSens)*offsetNote);	//24 is PitchBendSensBP
			
				int tmp_location=startTick+(int)(j*p);
				
				//remove last if duplicate tmp_location
				if(track.getPitchBendBPList().size()>1){
				ListValue last=track.getPitchBendBPList().get(track.getPitchBendBPList().size()-1);
				if(last.getLocation()==tmp_location && last.getValue()==0){
					
					track.getPitchBendBPList().remove(track.getPitchBendBPList().size()-1);
					log.trace("duplicated remove last:"+tmp_location);
				}
				}
				
				track.getPitchBendBPList().add(new ListValue(tmp_location,v));
				
				
				
			}
		
			//add end position 0
			track.getPitchBendBPList().add(new ListValue(startTick+noteLength,0));
		
			track.getPitchBendSensBPList().add(new ListValue(startTick,maxBendSens));
			}
		
			
			
		}
		
		int vmargin=200;
	
		int noteStart=track.getNotes().get(0).getStart();
		VocaloidNote lastNote=track.getNotes().get(track.getNotes().size()-1);
		int noteEnd=lastNote.getStart()+lastNote.getLength();
		
		if(detailDynamics && normalizeVolume){
		try{
	
		//normalize first otherwise.broken.
		List<ListValue> newList=normalizeDynamicsPBList(track.getDynamicsBPList(),noteStart,noteEnd,vmargin,normalizeVolumeRange,midi.getOffsetTick());
		track.getDynamicsBPList().clear();
		for (int i = 0; i <newList.size(); i++) {
			track.getDynamicsBPList().add(newList.get(i));
		}
		


		}catch(Exception e){
			e.printStackTrace();
		}
		
		}
		
		
		
		if(detailPitch && finalNormalizePitchRange!=0){
		
		List<ListValue> newPList=normalizePBList(track.getPitchBendBPList(),noteStart,noteEnd,vmargin,finalNormalizePitchRange,midi.getOffsetTick());
		track.getPitchBendBPList().clear();
		for (int i = 0; i <newPList.size(); i++) {
			track.getPitchBendBPList().add(newPList.get(i));
		}
		}

		
		//final first zero
		if(detailDynamics){
			if(track.getDynamicsBPList().size()>0){
				ListValue value=track.getDynamicsBPList().get(0);
				if(value.getLocation()!=offset){
					//initial zero
					ListValue zero=new ListValue(offset,0);//need zero other wise make noise
					track.getDynamicsBPList().add(0,zero);
				}
			}
		}
		
		return track;
	}
	
/*
 * special dynamics change methods
 * stragegy is 
 * +32 plus
 * x2 multiple
 * 90% compress
 */
	public  List<ListValue> normalizeDynamicsPBList(List<ListValue> list,int noteStart,int noteEnd,int margin,int range,int minTick){
		//empty do nothing
		if(list.size()==0){
			return list;
		}
		
		List<ListValue> newList=new ArrayList<ListValue>();
		ListValue[] lvalue=list.toArray(new ListValue[list.size()]);

		int startPosition=noteStart-margin;
		int endPosition=noteEnd+margin;
		//log.trace("s&e:"+noteStart+","+noteEnd);
		int[] volumeValues=new int[(int)((endPosition-startPosition))];
	//	log.trace(volumeValues.length);
		int lvalueIndex=0;
		int lastValue=lvalue[0].getValue();
		for (int j = 0; j < volumeValues.length; j++) {
			long position=startPosition+j;
			if(position<noteStart || position>noteEnd){
				//over note
				volumeValues[j]=0;
				//log.trace("p="+position+"v="+defaultVelocity);
			}else{
				volumeValues[j]=lastValue;
				
				if(lvalueIndex<lvalue.length-1 && position>lvalue[lvalueIndex+1].getLocation()){
					lvalueIndex++;
					lastValue=lvalue[lvalueIndex].getValue();
				}

			}
		}
		
		
		if(dynamicChangeStrategy!=null){
			ValueChangingTool vtool=new ValueChangingTool(127,dynamicChangeStrategy);
			volumeValues=vtool.change(volumeValues);
		}
		
		
		
		int[] normalizedVolume=new int[volumeValues.length];
		for (int j = 0; j < volumeValues.length; j++) {
			int c=0;
			int t=0;
		for(int k=j-range;k<j+range;k++){
			if(k>=0 &&k<volumeValues.length){
				c++;
				t+=volumeValues[k];
			}
		}
		normalizedVolume[j]=t/c;
		}
		
		

		
		
		int last=-1;
		for (int i = 0; i < volumeValues.length; i++) {
			int position=startPosition+i;
			if(last!=normalizedVolume[i]){
				if(position>=minTick){//if minus premeasure tick it make problem
					newList.add(new ListValue(position,normalizedVolume[i]));
				}
			last=normalizedVolume[i];
			}
			//track.getDynamicsBPList().add(new ListValue(position,volumeValues[i]));//TMP
		}
		return newList;
	}
	
	public static List<ListValue> normalizePBList(List<ListValue> list,int noteStart,int noteEnd,int margin,int range,int minTick){
		List<ListValue> newList=new ArrayList<ListValue>();
		ListValue[] lvalue=list.toArray(new ListValue[list.size()]);

		int startPosition=noteStart-margin;
		int endPosition=noteEnd+margin;
		//log.trace("s&e:"+noteStart+","+noteEnd);
		int[] volumeValues=new int[(int)((endPosition-startPosition))];
	//	log.trace(volumeValues.length);
		int lvalueIndex=0;
		int lastValue=lvalue[0].getValue();
		for (int j = 0; j < volumeValues.length; j++) {
			long position=startPosition+j;
			if(position<noteStart || position>noteEnd){
				//over note
				volumeValues[j]=0;
				//log.trace("p="+position+"v="+defaultVelocity);
			}else{
				volumeValues[j]=lastValue;
				
				if(lvalueIndex<lvalue.length-1 && position>lvalue[lvalueIndex+1].getLocation()){
					lvalueIndex++;
					lastValue=lvalue[lvalueIndex].getValue();
				}

			}
		}
		int[] normalizedVolume=new int[volumeValues.length];
		for (int j = 0; j < volumeValues.length; j++) {
			int c=0;
			int t=0;
		for(int k=j-range;k<j+range;k++){
			if(k>=0 &&k<volumeValues.length){
				c++;
				t+=volumeValues[k];
			}
		}
		normalizedVolume[j]=t/c;
		}
		
		int last=-1;
		for (int i = 0; i < volumeValues.length; i++) {
			int position=startPosition+i;
			if(last!=normalizedVolume[i]){
				if(position>=minTick){//if minus premeasure tick it make problem
					newList.add(new ListValue(position,normalizedVolume[i]));
				}
			last=normalizedVolume[i];
			}
			//track.getDynamicsBPList().add(new ListValue(position,volumeValues[i]));//TMP
		}
		return newList;
	}
	
	

	private boolean containPitchOverRange=true;//for round corner
	private double overDriveVolume=1;
	private boolean finalNormalizePitch=false;
	private int finalNormalizePitchRange=1;
	private int normalizePitchRange=1;
	private boolean normalizePitch=false;
	private boolean normalizeVolume=false;
	private int normalizeVolumeRange=1;	
	private int[] downHamoriScale=null;
	private int[] upHamoriScale=null;
	private int upMixer=-200;
	private int downMixer=-200;
	//private int[] downScale=Scale.ROOT_ONLY_CODE;
	//private int[] upScale=Scale.CODE_MAJOR;
	
	private VocaloidMIDI midi;
	
	/*
	 * breath support
	 * @see jp.sourceforge.akjrcp.snack.PitchToMIDI#toNoteDataList(jp.sourceforge.akjrcp.snack.ESPS[], jp.sourceforge.akjrcp.subtitle.StandardSubObject[], int[])
	 */
	protected List<NoteData> toNoteDataList(ESPS[] espses,StandardSubObject[] subtitles,int[] currentScaleFilter){
		 NoteData notes[]=espsesToNote(espses,currentScaleFilter);
        List<NoteData> subNotes[]=new ArrayList[subtitles.length];
        if(subtitles.length>0){
        		for (int i = 0; i < notes.length; i++) {
        			CHECK:for (int j = 0; j < subtitles.length; j++) {
        					if(inTime(notes[i],subtitles[j])){
								log.trace("intime:"+noteToMillisecond(notes[i].getStart())+"-"+noteToMillisecond(notes[i].getEnd()));
								if(subNotes[j]==null){
									subNotes[j]=new ArrayList<NoteData>();
								}
							//	log.trace(subtitles[j].getText()+","+i);
								subNotes[j].add(notes[i]);
								break CHECK;
							}
						}
        		}
        }
        List<NoteData> noteDataList=new ArrayList<NoteData>();
        for(int i=0;i<subNotes.length;i++){
        	if(isBreath(subtitles[i].getText()) && ignoreBreathDynamics){
        	//set fix breath
        		//set at least
    		    int startTick=timeToTick(subtitles[i].getStartTime());
    			int endTick=timeToTick(subtitles[i].getEndTime());
    			//log.trace("d:"+defaultBreathDynamics);
    			NoteData data=new NoteData(startTick, endTick, filterdNote(defaultNote, true, currentScaleFilter), defaultBreathDynamics);
    			data.setComment(subtitles[i].getText());
    			noteDataList.add(data);	
        	}else{
        	//other normal phonetics	
        	
        	if(subNotes[i]!=null){
        		addAverageNote(noteDataList,subNotes[i],subtitles[i],currentScaleFilter);
        	}else{
        		if(forceInsert){
        			//set at least
        			int minTick=pertick/16;//64 note  //int tick=30;//32 note , tempo 240/16 
        			int startTick=timeToTick(subtitles[i].getStartTime());
        			int endTick=timeToTick(subtitles[i].getEndTime());
        			int stick=startTick+(endTick-startTick-minTick)/2;
        			log.info("add empty note:s="+stick);
        			NoteData data=new NoteData(stick, stick+minTick, filterdNote(defaultNote, true, currentScaleFilter), defaultVelocity);
        			data.setComment(subtitles[i].getText());
        			noteDataList.add(data);
        		}
        	}
        }
        }
        return noteDataList;
	}
	
	public boolean isBreath(String phonetics){
		return phonetics.startsWith("br");
	}
	
	public void makeVocaloidMIDI(ESPS[] espses,StandardSubObject[] subtitles,File file) throws IOException{
		midi=new VocaloidMIDI();
		midi.getMaster().setPreMeasure(preMeasure);
		//set xx
		
		List<NoteData> noteDataList=toNoteDataList(espses,subtitles,scaleFilter);
		if(noteDataList.size()>0){
			
			
			
			midi.setTempo(getTempo());
			int offset=midi.getOffsetTick();	//480*4*4
			
			//main
			log.trace("start create vocaloid midi track");
			VocaloidTrack mainTrack=createVocaloidTrack(offset,noteDataList,shiftNote);
			midi.addTrack(mainTrack);
			if(autoNNPhonetics){
				VocaloidNote notes[]=mainTrack.getNotes().toArray(new VocaloidNote[mainTrack.getNotes().size()]);
				for (int i = 0; i < notes.length; i++) {//last one ignore
					//log.trace("'"+notes[i].getPhonetics()+"'");
					if(notes[i].getPhonetics().equals("n")){
						if(i==notes.length-1){
							//default n\ 
							notes[i].setPhonetics(PhoneticsUtils.N_LARGE_BS);
							//log.trace("next=,replace="+PhoneticsUtils.N_LARGE_BS);
						}else{
						String newN=AutoPhoneticsUtils.toNNPhonetics(notes[i+1].getPhonetics());
						notes[i].setPhonetics(newN);
					//	log.trace("next="+notes[i+1].getLabel()+",replace="+newN);
						}
					}
				}
			}
			
			if(separateBreathTrack){
				
				VocaloidTrack breath=(VocaloidTrack) mainTrack.clone();
				VocaloidNote notes[]=mainTrack.getNotes().toArray(new VocaloidNote[mainTrack.getNotes().size()]);
				List<VocaloidNote> breathNote=new ArrayList<VocaloidNote> ();
				for (int i = 0; i <notes.length; i++) {
					VocaloidNote note=notes[i];
					if(note.getPhonetics().startsWith("br")){
						breathNote.add(note);
						mainTrack.getNotes().remove(note);
					}
				}
				
				if(ignoreBreathDynamics){
					breath.getDynamicsBPList().clear();
					breath.getDynamicsBPList().add(new ListValue(offset,defaultBreathDynamics));
				}
				
				if(breathNote.size()>0){
					breath.getNotes().removeAll(breath.getNotes());
					for (int i = 0; i <breathNote.size(); i++) {
						VocaloidNote note=breathNote.get(i);
						breath.getNotes().add(note);
					}
					midi.addTrack(breath);
					if(doubleBreathOnSplit){
						VocaloidTrack b2=doubleBreathTrack(midi,breath);
						b2.setName("breath2");
					}
				}
				
				breath.setName("breath1");
				
			}
			
			//all track removed to breath track.delete main
			if(mainTrack.getNotes().size()==0){
				midi.getTracks().remove(mainTrack);
			}
			
			
			//if breath only ,main already empty
			if(copyAsBreathTrack && mainTrack.getNotes().size()>0){
				List<NoteData> upnoteDataList=toNoteDataList(espses,subtitles,scaleFilter);
				VocaloidTrack breath=(VocaloidTrack) mainTrack.clone();
				List<VocaloidNote> notes=breath.getNotes();
				for (int i = 0; i <notes.size(); i++) {
					VocaloidNote note=notes.get(i);
					note.setPhonetics(copyAsBreathPhonetics);
					note.setLabel(copyAsBreathPhonetics);
				}
				
				if(ignoreBreathDynamics){
					breath.getDynamicsBPList().clear();
					breath.getDynamicsBPList().add(new ListValue(offset,defaultBreathDynamics));
				}
				
				midi.addTrack(breath);
				
				breath.setName("breath3");
				if(doubleBreathTrack){
					VocaloidTrack b2=doubleBreathTrack(midi,breath);
					b2.setName("breath4");
				}
				
				//remove breath note from main track.duplicate make noise.
				VocaloidNote mainNotes[]=mainTrack.getNotes().toArray(new VocaloidNote[mainTrack.getNotes().size()]);
				for (int i = 0; i < mainNotes.length; i++) {
					if(isBreath(mainNotes[i].getPhonetics())){
						mainTrack.getNotes().remove(mainNotes[i]);
					}
				}
			}
			
			//all track removed to breath track.delete main
			if(mainTrack.getNotes().size()==0){
				midi.getTracks().remove(mainTrack);
			}
			

			
			if(addStereoTrack){
				//clone node
				List<NoteData> upnoteDataList=toNoteDataList(espses,subtitles,scaleFilter);
				List<NoteData> rightTrack=new ArrayList<NoteData>();
				List<NoteData> leftTrack=new ArrayList<NoteData>();
				for (int i = 0; i <upnoteDataList.size(); i++) {
					if(i%2==0){
						rightTrack.add(upnoteDataList.get(i));
					}else{
						leftTrack.add(upnoteDataList.get(i));
					}
				}
				VocaloidTrack rtrack=createVocaloidTrack(offset,rightTrack,shiftNote);
				rtrack.setPanpot(stereoTrackPan);
				rtrack.setFeder(stereoTrackMixer);
				rtrack.setName("right");
				VocaloidTrack ltrack=createVocaloidTrack(offset,leftTrack,shiftNote);
				ltrack.setPanpot(-stereoTrackPan);
				ltrack.setFeder(stereoTrackMixer);
				ltrack.setName("left");
				midi.addTrack(rtrack);
				midi.addTrack(ltrack);
			}
			
		
			//upper
			if(upHamoriScale!=null){
			List<NoteData> upnoteDataList=toNoteDataList(espses,subtitles,upHamoriScale);
			VocaloidTrack uptrack=createVocaloidTrack(offset,upnoteDataList,shiftNote+12);
			uptrack.setName("up");
			uptrack.setFeder(upMixer);
			midi.addTrack(uptrack);
			}
			//down
			if(downHamoriScale!=null){
			List<NoteData> downupnoteDataList=toNoteDataList(espses,subtitles,downHamoriScale);
			VocaloidTrack downtrack=createVocaloidTrack(offset,downupnoteDataList,shiftNote-12);
			downtrack.setName("down");
			downtrack.setFeder(downMixer);
			midi.addTrack(downtrack);
			}
			
			try {
				VocaloidSystem.write(midi, file);
			} catch (IOException e) {
				// TODO �����������ꂽ catch �u���b�N
				e.printStackTrace();
			}
		}else{
			throw new IOException("data is empty");
		}
	}
	
	private VocaloidTrack doubleBreathTrack(VocaloidMIDI midi,VocaloidTrack breath){
		VocaloidTrack breath2=(VocaloidTrack) breath.clone();
		breath2.getNotes().clear();
		VocaloidNote[] bnotes=breath.getNotes().toArray(new VocaloidNote[breath.getNotes().size()]);
		for (int i = 0; i < bnotes.length; i++) {
			if(i%2==1){
				bnotes[i].setLabel(copyAsBreathPhonetics2);
				bnotes[i].setPhonetics(copyAsBreathPhonetics2);
				breath2.addNote(bnotes[i]);
				breath.getNotes().remove(bnotes[i]);
			}
		}
		if(	breath2.getNotes().size()>0){
			midi.addTrack(breath2);
		}
		return breath2;
	}
	

	
	public boolean shouldNoVoice(NoteData note){
		int noVoices=0;
		int s=note.getPitchNoteDatas().size()/2;
		int index=0;
		for(int j=s;j<note.getPitchNoteDatas().size();j++){
			PitchNoteData data=note.getPitchNoteDatas().get(j);
			index++;
			if(data.isNoVoice()){
				noVoices++;
			}
		}
		//if have voice,
		return index==noVoices;
	}

	public int getMaxBendSens() {
		return maxBendSens;
	}

	public void setMaxBendSens(int maxBendSens) {
		this.maxBendSens = maxBendSens;
	}

	public int getPreMeasure() {
		return preMeasure;
	}

	public void setPreMeasure(int preMeasure) {
		this.preMeasure = preMeasure;
	}

	public int getGen() {
		return gender;
	}

	public void setGen(int gender) {
		this.gender = gender;
	}

	public boolean isDetailPitch() {
		return detailPitch;
	}

	public void setDetailPitch(boolean detailPitch) {
		this.detailPitch = detailPitch;
	}

	public boolean isDetailDynamics() {
		return detailDynamics;
	}

	public void setDetailDynamics(boolean detailDynamics) {
		this.detailDynamics = detailDynamics;
	}
	public int getDetailLevel() {
		return detailLevel;
	}
	public void setDetailLevel(int detailLevel) {
		this.detailLevel = detailLevel;
	}


	public int[] getDownHamoriScale() {
		return downHamoriScale;
	}


	public void setDownHamoriScale(int[] downHamoriScale) {
		this.downHamoriScale = downHamoriScale;
	}


	public int[] getUpHamoriScale() {
		return upHamoriScale;
	}


	public void setUpHamoriScale(int[] upHamoriScale) {
		this.upHamoriScale = upHamoriScale;
	}


	public int getUpMixer() {
		return upMixer;
	}


	public void setUpMixer(int upMixer) {
		this.upMixer = upMixer;
	}


	public int getDownMixer() {
		return downMixer;
	}


	public void setDownMixer(int downMixer) {
		this.downMixer = downMixer;
	}


	public int getNormalizePitchRange() {
		return normalizePitchRange;
	}


	public void setNormalizePitchRange(int normalizePitchRange) {
		this.normalizePitchRange = normalizePitchRange;
	}


	public boolean isNormalizePitch() {
		return normalizePitch;
	}


	public void setNormalizePitch(boolean normalizePitch) {
		this.normalizePitch = normalizePitch;
	}


	public boolean isNormalizeVolume() {
		return normalizeVolume;
	}


	public void setNormalizeVolume(boolean normalizeVolume) {
		this.normalizeVolume = normalizeVolume;
	}


	public int getNormalizeVolumeRange() {
		return normalizeVolumeRange;
	}


	public void setNormalizeVolumeRange(int normalizeVolumeRange) {
		this.normalizeVolumeRange = normalizeVolumeRange;
	}


	public boolean isContainPitchOverRange() {
		return containPitchOverRange;
	}


	public void setContainPitchOverRange(boolean containPitchOverRange) {
		this.containPitchOverRange = containPitchOverRange;
	}


	public int getFinalNormalizePitchRange() {
		return finalNormalizePitchRange;
	}


	public void setFinalNormalizePitchRange(int finalNormalizePitchRange) {
		this.finalNormalizePitchRange = finalNormalizePitchRange;
	}


	public boolean isFinalNormalizePitch() {
		return finalNormalizePitch;
	}


	public void setFinalNormalizePitch(boolean finalNormalizePitch) {
		this.finalNormalizePitch = finalNormalizePitch;
	}


	public String getDynamicChangeStrategy() {
		return dynamicChangeStrategy;
	}


	public void setDynamicChangeStrategy(String dynamicChangeStrategy) {
		this.dynamicChangeStrategy = dynamicChangeStrategy;
	}


	public boolean isAddStereoTrack() {
		return addStereoTrack;
	}


	public void setAddStereoTrack(boolean addStereoTrack) {
		this.addStereoTrack = addStereoTrack;
	}





	public int getBre() {
		return bre;
	}

	public void setBre(int bre) {
		this.bre = bre;
	}

	public int getBri() {
		return bri;
	}

	public void setBri(int bri) {
		this.bri = bri;
	}

	public int getCle() {
		return cle;
	}

	public void setCle(int cle) {
		this.cle = cle;
	}

	public int getOpe() {
		return ope;
	}

	public void setOpe(int ope) {
		this.ope = ope;
	}

	public int getPor() {
		return por;
	}

	public void setPor(int por) {
		this.por = por;
	}

	public boolean isSeparateBreathTrack() {
		return separateBreathTrack;
	}

	public void setSeparateBreathTrack(boolean separateBreathTrack) {
		this.separateBreathTrack = separateBreathTrack;
	}

	public boolean isCopyAsBreathTrack() {
		return copyAsBreathTrack;
	}

	public void setCopyAsBreathTrack(boolean copyAsBreathTrack) {
		this.copyAsBreathTrack = copyAsBreathTrack;
	}

	public String getCopyAsBreathPhonetics() {
		return copyAsBreathPhonetics;
	}

	public void setCopyAsBreathPhonetics(String copyAsBreathPhonetics) {
		this.copyAsBreathPhonetics = copyAsBreathPhonetics;
	}

	public String getCopyAsBreathPhonetics2() {
		return copyAsBreathPhonetics2;
	}

	public void setCopyAsBreathPhonetics2(String copyAsBreathPhonetics2) {
		this.copyAsBreathPhonetics2 = copyAsBreathPhonetics2;
	}

	public boolean isDoubleBreathTrack() {
		return doubleBreathTrack;
	}

	public void setDoubleBreathTrack(boolean doubleBreathTrack) {
		this.doubleBreathTrack = doubleBreathTrack;
	}

	public boolean isIgnoreBreathDynamics() {
		return ignoreBreathDynamics;
	}

	public void setIgnoreBreathDynamics(boolean ignoreBreathDynamics) {
		this.ignoreBreathDynamics = ignoreBreathDynamics;
	}

	public int getDefaultBreathDynamics() {
		return defaultBreathDynamics;
	}

	public void setDefaultBreathDynamics(int defaultBreathDynamics) {
		this.defaultBreathDynamics = defaultBreathDynamics;
	}

	public int getStereoTrackPan() {
		return stereoTrackPan;
	}

	public void setStereoTrackPan(int stereoTrackPan) {
		this.stereoTrackPan = stereoTrackPan;
	}

	public int getStereoTrackMixer() {
		return stereoTrackMixer;
	}

	public void setStereoTrackMixer(int stereoTrackMixer) {
		this.stereoTrackMixer = stereoTrackMixer;
	}

	public boolean isAutoNNPhonetics() {
		return autoNNPhonetics;
	}

	public void setAutoNNPhonetics(boolean autoNNPhonetics) {
		this.autoNNPhonetics = autoNNPhonetics;
	}

	public boolean isDoubleBreathOnSplit() {
		return doubleBreathOnSplit;
	}

	public void setDoubleBreathOnSplit(boolean doubleBreathOnSplit) {
		this.doubleBreathOnSplit = doubleBreathOnSplit;
	}



}
